package Parmcfg;

import Commom.OsSelect;
import NetSDKDemo.HCNetSDK;
import com.sun.jna.Native;
import util.LogManager;
import view.ScanCameraFrame;

import javax.swing.*;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @create 2020-07-27-10:42
 */
public class TestDemo {
    static HCNetSDK hCNetSDK = null;
    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static Path logDir;

    /**
     * 动态库加载
     *
     * @return
     */
    public static boolean createSDKInstance() {
        if (hCNetSDK == null) {
            synchronized (HCNetSDK.class) {
                String strDllPath = "";
                try {
                    if (OsSelect.isWindows())
                        //win系统加载SDK库路径
                        strDllPath = System.getProperty("user.dir") + "\\lib\\HCNetSDK.dll";
                    else if (OsSelect.isLinux())
                        //Linux系统加载SDK库路径
                        strDllPath = System.getProperty("user.dir") + "/lib/libhcnetsdk.so";
                    hCNetSDK = (HCNetSDK) Native.loadLibrary(strDllPath, HCNetSDK.class);
                } catch (Exception ex) {
                    System.out.println("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
                    return false;
                }
            }
        }
        return true;
    }

    public static void main(String[] args) {
        // 设置全局异常捕获
        setupGlobalExceptionHandler();
        SwingUtilities.invokeLater(() -> new ScanCameraFrame().setVisible(true));
        if (hCNetSDK == null) {
            if (!createSDKInstance()) {
                LogManager.getInstance().appendLog("Load SDK fail!");
            } else {
                LogManager.getInstance().appendLog("Load SDK success!");
            }
        }
        //linux系统建议调用以下接口加载组件库
        if (OsSelect.isLinux()) {
            HCNetSDK.BYTE_ARRAY ptrByteArray1 = new HCNetSDK.BYTE_ARRAY(256);
            HCNetSDK.BYTE_ARRAY ptrByteArray2 = new HCNetSDK.BYTE_ARRAY(256);
            //这里是库的绝对路径，请根据实际情况修改，注意改路径必须有访问权限
            String strPath1 = System.getProperty("user.dir") + "/lib/libcrypto.so.1.1";
            String strPath2 = System.getProperty("user.dir") + "/lib/libssl.so.1.1";
            System.arraycopy(strPath1.getBytes(), 0, ptrByteArray1.byValue, 0, strPath1.length());
            ptrByteArray1.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(HCNetSDK.NET_SDK_INIT_CFG_LIBEAY_PATH, ptrByteArray1.getPointer());
            System.arraycopy(strPath2.getBytes(), 0, ptrByteArray2.byValue, 0, strPath2.length());
            ptrByteArray2.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(HCNetSDK.NET_SDK_INIT_CFG_SSLEAY_PATH, ptrByteArray2.getPointer());
            String strPathCom = System.getProperty("user.dir") + "/lib/";
            HCNetSDK.NET_DVR_LOCAL_SDK_PATH struComPath = new HCNetSDK.NET_DVR_LOCAL_SDK_PATH();
            System.arraycopy(strPathCom.getBytes(), 0, struComPath.sPath, 0, strPathCom.length());
            struComPath.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(HCNetSDK.NET_SDK_INIT_CFG_SDK_PATH, struComPath.getPointer());
        }
        //SDK初始化，一个程序进程只需要调用一次
        hCNetSDK.NET_DVR_Init();
        LogManager.getInstance().appendLog("设置异常消息回调成功");

        //启用SDK写日志
        hCNetSDK.NET_DVR_SetLogToFile(3, "./sdkLog", false);
    }

    private static void setupGlobalExceptionHandler() {
        // 捕获主线程和其他线程中的未捕获异常
        Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
            String errorMessage = "线程 [" + thread.getName() + "] 中发生异常: " + throwable.getMessage();
            LogManager.getInstance().appendLog(errorMessage);

            if (logDir == null) {
                logDir = Paths.get(System.getProperty("user.dir"), "logs");
                try {
                    Files.createDirectories(logDir);
                } catch (IOException ignored) {
                }
            }
            // 追加异常详细信息到日志文件
            try (BufferedWriter writer = new BufferedWriter(new FileWriter(logDir.resolve("error.log").toString(), true))) {

                writer.write(LocalDateTime.now().format(formatter) + " - " + errorMessage + "\n");
                throwable.printStackTrace(new PrintWriter(writer));
            } catch (Exception e) {
                System.out.println("无法写入异常日志: " + e.getMessage());
            }
        });

        // 捕获 Swing UI 线程的异常
        SwingUtilities.invokeLater(() -> {
            Thread.currentThread().setUncaughtExceptionHandler((thread, throwable) -> {
                String errorMessage = "UI 线程异常: " + throwable.getMessage();
                LogManager.getInstance().appendLog(errorMessage);
            });
        });
    }

    /**
     * 登录设备，支持 V40 和 V30 版本，功能一致。
     *
     * @param ip   设备IP地址
     * @param port SDK端口，默认为设备的8000端口
     * @param user 设备用户名
     * @param psw  设备密码
     * @return 登录成功返回用户ID，失败返回-1
     */
    public static int loginDevice(String ip, short port, String user, String psw) {
        // 创建设备登录信息和设备信息对象
        HCNetSDK.NET_DVR_USER_LOGIN_INFO loginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();
        HCNetSDK.NET_DVR_DEVICEINFO_V40 deviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();

        // 设置设备IP地址
        byte[] deviceAddress = new byte[HCNetSDK.NET_DVR_DEV_ADDRESS_MAX_LEN];
        byte[] ipBytes = ip.getBytes();
        System.arraycopy(ipBytes, 0, deviceAddress, 0, Math.min(ipBytes.length, deviceAddress.length));
        loginInfo.sDeviceAddress = deviceAddress;

        // 设置用户名和密码
        byte[] userName = new byte[HCNetSDK.NET_DVR_LOGIN_USERNAME_MAX_LEN];
        byte[] password = psw.getBytes();
        System.arraycopy(user.getBytes(), 0, userName, 0, Math.min(user.length(), userName.length));
        System.arraycopy(password, 0, loginInfo.sPassword, 0, Math.min(password.length, loginInfo.sPassword.length));
        loginInfo.sUserName = userName;

        // 设置端口和登录模式
        loginInfo.wPort = port;
        loginInfo.bUseAsynLogin = false; // 同步登录
        loginInfo.byLoginMode = 0; // 使用SDK私有协议

        // 执行登录操作
        int userID = hCNetSDK.NET_DVR_Login_V40(loginInfo, deviceInfo);
        if (userID == -1) {
            LogManager.getInstance().appendLog("登录失败，错误码为: " + hCNetSDK.NET_DVR_GetLastError());
            System.err.println("登录失败，错误码为: " + hCNetSDK.NET_DVR_GetLastError());
        } else {
            System.out.println(ip + " 设备登录成功！");
            LogManager.getInstance().appendLog(ip + " 设备登录成功！");
            // 处理通道号逻辑
            int startDChan = deviceInfo.struDeviceV30.byStartDChan;
            System.out.println("预览起始通道号: " + startDChan);
            LogManager.getInstance().appendLog("预览起始通道号: " + startDChan);
        }
        return userID; // 返回登录结果
    }

    public static void logout(int lUserID) {
        if (hCNetSDK.NET_DVR_Logout(lUserID)) {
            System.out.println("注销成功");
            LogManager.getInstance().appendLog("注销成功!");
        }
    }

    public static void cleanUp() {
        //释放SDK资源，程序退出时调用，只需要调用一次
        hCNetSDK.NET_DVR_Cleanup();
        LogManager.getInstance().appendLog("释放SDK资源!");
    }
}


